package development.game;

import state.GameAlert;
import state.GameConstants;
import state.GameForm;
import state.GameGlobal;
import state.GameImage;
import state.Graphics;
import state.Key;
import state.TimerListener;
import state.font.FontManager;
import state.font.ImageText;
import state.socket.DataPackage;
import state.socket.DataReceiveListener;
import state.util.GameColor;
import state.util.Hashtable;
import state.util.ImageUtil;
import state.util.NumberUtil;
import state.util.TwoDimensionInt;
import state.util.array.IntArray;
import state.util.array.StringArray;
import development.Constants;
import development.DrawUtils;
import development.Global;
import development.bean.Game;
import development.group.FrmGroupListTableFreeUserChat;
import development.group.FrmGroupTableFreeUserFriend;
import development.socket.SocketClientUtil;

public class FrmCaro extends GameForm implements TimerListener, DataReceiveListener {
  private final int MOVE_REQUEST = 1001; // Gửi thông tin về nước đã đi

  private final int MOVE_ERROR_RESPONSE = 2001; // Báo lại cho ng chơi vừa đánh là nước đánh không được chấp nhận
  private final int MOVE_NOTIFY_RESPONSE = 2002; // Báo nước đi của người vừa đánh
  private final int WIN_GAME_NOTIFY_RESPONSE = 2005; // Báo cho các user về user đã thắng và danh sách các nước đi thắng
  private final int INIT_DATA_RESPONSE = 2007; // Thiết đặt các thông số từ server

  private final int NOT_YOUR_TURN_ERROR = 3001;
  private final int MOVE_IN_NOT_ALLOW_POSITION = 3002;

  private final int NORMAL_WIN_REASON = 4001;
  private final int OPPONENT_RESIGN_WIN_REASON = 4002;
  private final int OPPONENT_TIMEOUT_WIN_REASON = 4003;
  
  private final int WAIT_FOR_INIT_STATUS = 0;
  private final int PLAY_STATUS = 1;
  private final int CHAT_STATUS = 2;
  private final int SHOW_WIN_OR_LOST_ALERT_STATUS = 3;
  private final int SHOW_FINAL_RESULL = 4;

  private final int NUMBER_OF_ROW = 100;
  private final int NUMBER_OF_COLUMN = 100;
  private final int ROUND_SIDE = -1;
  private final int CROSS_SIDE = 1;

  public final int CELL_SIZE = 15;

  private int TIME_PER_MOVE;

  private int NUMBER_COLUMN_DISPLAY;
  private int NUMBER_ROW_DISPLAY;
  public int BOARD_DX;
  public int BOARD_DY;

  private GameImage lastMoveImage;
  private GameImage pointerImage;
  private GameImage numberBgImage;
  private GameImage matnaImage;
  private GameImage starImage;
  private GameImage thangImage;
  private GameImage thuaImage;

  private int currentGameStatus;

  private int[][] matrix = new int[NUMBER_OF_COLUMN][NUMBER_OF_ROW];
  private int currentX;
  private int currentY;

  private int currentTurn;
  private int mySide;
  private int opponentSide;
  private String oponentName;

  private boolean isTurnOnAutoCamera;
  private int desX;
  private int desY;
  private int dRow;
  private int dColumn;
  private int minRow;
  private int maxRow;
  private int minColumn;
  private int maxColumn;

  private int timeMove;
  private int count;

  private int winSide;
  private int winReason;
  private int winPointX1;
  private int winPointY1;
  private int winPointX2;
  private int winPointY2;
  private String moneyChangeMessage = "";
  private int moneyChangeIndex;
  private String[] moneyChangePoint = new String[2];

  private ImageText text8;
  
  private static GameForm singleton;
  
  public static GameForm instance() {
    if (singleton == null) {
      singleton = new FrmCaro();
    }
    return singleton;
  }

  public void init(Hashtable inputParameters) {
    pointerImage = ImageUtil.getImage(Constants.NEW_IMAGE_CATEGORY, "caro_pointer.png");
    lastMoveImage = ImageUtil.getImage(Constants.NEW_IMAGE_CATEGORY, "move_small.png");
    starImage = ImageUtil.getImage(Constants.HIEU_UNG_IMAGE_CATEGORY, "HieuUng.png");
    matnaImage = ImageUtil.joinAndCreateImages(ImageUtil.getImage(Constants.HIEU_UNG_IMAGE_CATEGORY, "pxiel_nen.png"), GameConstants.SCREEN_WIDTH, GameConstants.SCREEN_HEIGHT - 20);
    thuaImage = ImageUtil.getImage(Constants.HIEU_UNG_IMAGE_CATEGORY, "icon_lose.png");
    thangImage = ImageUtil.getImage(Constants.HIEU_UNG_IMAGE_CATEGORY, "icon_win.png");
    numberBgImage = ImageUtil.getImage(Constants.NEW_IMAGE_CATEGORY, "Nen_So.png");

    if (GameConstants.IS_240x320_SCREEN) {
      BOARD_DX = 0;
      BOARD_DY = 0;
      NUMBER_COLUMN_DISPLAY = 18;
      NUMBER_ROW_DISPLAY = 21;
    } else {
      BOARD_DX = 0;
      BOARD_DY = 0;
      NUMBER_COLUMN_DISPLAY = 19;
      NUMBER_ROW_DISPLAY = 17;
    }

    dRow = 43;
    dColumn = 43;
    currentX = dRow + NUMBER_COLUMN_DISPLAY / 2;
    currentY = dColumn + NUMBER_ROW_DISPLAY / 2;
    
    minRow = currentY;
    maxRow = currentY;
    minColumn = currentX;
    maxColumn = currentX;
    count = 0;

    winPointX1 = 0;
    winPointY1 = 0;
    winPointX2 = 0;
    winPointY2 = 0;
    moneyChangeMessage = "";
    moneyChangeIndex = -1;

    recalculateGround(currentX, currentY);

    for (int i = 0; i < NUMBER_OF_COLUMN; i++) {
      for (int j = 0; j < NUMBER_OF_ROW; j++) {
        matrix[i][j] = 0;
      }
    }
    text8 = FontManager.getFont(FontManager.FONT_SIZE_8);

    isTurnOnAutoCamera = false;
    desX = 0;
    desY = 0;
    setTimerListener(this);
    
    TwoDimensionInt CHAT_LOCATION_240x320 = new TwoDimensionInt(2, 2);
    CHAT_LOCATION_240x320.setRow(0, new IntArray(new int[] {140, 205}, 2));
    CHAT_LOCATION_240x320.setRow(1, new IntArray(new int[] {5, 2}, 2));
    
    TwoDimensionInt CHAT_LOCATION_320x240 = new TwoDimensionInt(2, 2);
    CHAT_LOCATION_320x240.setRow(0, new IntArray(new int[] {220, 125}, 2));
    CHAT_LOCATION_320x240.setRow(1, new IntArray(new int[] {5, 2}, 2));
    
    Global.initChatComponent(CHAT_LOCATION_240x320, CHAT_LOCATION_320x240);
    _manager.enableTouchPad();
  }

  public void onRecieveData(DataPackage dataPackage) {
    int header = dataPackage.getHeader();
    switch (header) {
    case MOVE_NOTIFY_RESPONSE:
      int side = dataPackage.nextInt();
      int x = dataPackage.nextInt();
      int y = dataPackage.nextInt();
      fire(side, x, y);
      currentTurn = mySide;
      break;
    case WIN_GAME_NOTIFY_RESPONSE:
      winSide = dataPackage.nextInt();
      winReason = dataPackage.nextInt();
      winPointX1 = dataPackage.nextInt();
      winPointY1 = dataPackage.nextInt();
      winPointX2 = dataPackage.nextInt();
      winPointY2 = dataPackage.nextInt();
      moneyChangePoint[0] = String.valueOf(dataPackage.nextInt());
      moneyChangePoint[1] = String.valueOf(dataPackage.nextInt());
      
      if (winSide == mySide) {
        moneyChangeMessage = "Thưởng " + moneyChangePoint[0] + " gold";
      } else {
        moneyChangeMessage = "Trừ " + Math.abs(NumberUtil.parseInt(moneyChangePoint[0])) + " gold";
      }
      moneyChangeIndex = 0;
      
      if (Global.systemCanvas.frmCurrent != FrmCaro.instance()) {
        return;
      }

      // Kiểm tra xem là thắng cuộc trong trường hợp nào
      if (winReason == NORMAL_WIN_REASON) {
        currentGameStatus = SHOW_WIN_OR_LOST_ALERT_STATUS;
      } else if (winReason == OPPONENT_RESIGN_WIN_REASON) {
        GameGlobal.alert.showAlert1(this, GameAlert.OK_TYPE, StringArray.create1("Đối thủ đã bỏ cuộc", "Bạn đã thắng"), 97);
      } else if (winReason == OPPONENT_TIMEOUT_WIN_REASON) {
        if (winSide == mySide) {
          GameGlobal.alert.showAlert1(this, GameAlert.OK_TYPE, StringArray.create1("Đối thủ đã hết thời gian", "Bạn đã thắng"), 97);
        } else {
          GameGlobal.alert.showAlert1(this, GameAlert.OK_TYPE, StringArray.create1("Thời gian cho nước đi đã hết", "Bạn đã thua"), 97);
        }
      }
      break;
    case MOVE_ERROR_RESPONSE:
      int error = dataPackage.nextInt();
      if (error == NOT_YOUR_TURN_ERROR) {
        GameGlobal.alert.showAlert(this, GameAlert.OK_TYPE, "Không phải lượt đánh của bạn");
      } else if (error == MOVE_IN_NOT_ALLOW_POSITION) {
        GameGlobal.alert.showAlert(this, GameAlert.OK_TYPE, "Nước đi không hợp lệ");
      } else {
        GameGlobal.alert.showAlert(this, GameAlert.OK_TYPE, "Nước đi không được phép");
      }
      break;
    case INIT_DATA_RESPONSE:
      TIME_PER_MOVE = dataPackage.nextInt();
      timeMove = TIME_PER_MOVE;

      for (int i = 0; i < 2; i++) {
        int side1 = dataPackage.nextInt();
        String userName = dataPackage.nextString();
        if (userName.equals(Global.currentUser.getName())) {
          mySide = side1;
        } else {
          oponentName = userName;
          opponentSide = side1;
        }
      }
      if (mySide == CROSS_SIDE) {
        currentTurn = mySide;
      }
      currentGameStatus = PLAY_STATUS;
      break;
    }
  }
  
  private void drawMoneyChangeNotification(Graphics g) {
    if (moneyChangeIndex > 0) {
      g.setColor(0xFFA500);
      g.fillRoundRect(GameConstants.SCREEN_WIDTH / 2 - 80, GameConstants.SCREEN_HEIGHT / 2 - 22, 160, 24, 5, 5);
      text8.drawString2(g, moneyChangeMessage, GameColor.WHITE_CODE, GameConstants.SCREEN_WIDTH / 2, GameConstants.SCREEN_HEIGHT / 2 - 20, GameConstants.TOP_HCENTER_ANCHOR);
    }
  }

  public void draw(Graphics g) {
    DrawUtils.drawBackground(g);
    
    // Vẽ ô bàn đấu
    g.setColor(0x8B4E4D);
    g.fillRect(BOARD_DX, BOARD_DY, NUMBER_COLUMN_DISPLAY * CELL_SIZE, NUMBER_ROW_DISPLAY * CELL_SIZE);
    g.setColor(0xB07C7C);
    for (int i = 0; i <= NUMBER_ROW_DISPLAY; i++) {
      g.drawLine(BOARD_DX, BOARD_DY + CELL_SIZE * i, BOARD_DX + CELL_SIZE * NUMBER_COLUMN_DISPLAY, BOARD_DY + CELL_SIZE * i);
    }
    for (int j = 0; j <= NUMBER_COLUMN_DISPLAY; j++) {
      g.drawLine(BOARD_DX + CELL_SIZE * j, BOARD_DY, BOARD_DX + CELL_SIZE * j, BOARD_DY + CELL_SIZE * NUMBER_ROW_DISPLAY);
    }

    // Vẽ các điểm đã đánh của cả 2 bên
    for (int i = 0; i < NUMBER_COLUMN_DISPLAY; i++) {
      for (int j = 0; j < NUMBER_ROW_DISPLAY; j++) {
        text8.setBold(true);
        if (matrix[dColumn + i][dRow + j] == CROSS_SIDE) {
          text8.drawOneChar(g, 'x', GameColor.YELLOW_CODE, BOARD_DX + i * CELL_SIZE + 4, BOARD_DY + j * CELL_SIZE - 4);
        } else if (matrix[dColumn + i][dRow + j] == ROUND_SIDE) {
          text8.drawOneChar(g, 'o', GameColor.GREEN_CODE, BOARD_DX + i * CELL_SIZE + 4, BOARD_DY + j * CELL_SIZE - 4);
        }
        text8.setBold(false);
      }
    }

    // Vẽ nước đánh trước đó
    if (currentTurn == mySide) {
      g.drawImage(lastMoveImage, BOARD_DX + CELL_SIZE / 2 + CELL_SIZE * (desX - dColumn), BOARD_DY + CELL_SIZE / 2 + CELL_SIZE * (desY - dRow), GameConstants.CENTER_ANCHOR);
    }
    
    // Draw User info
    DrawUtils.drawUserInfo(g, oponentName, 5, 2, false);
    if (Constants.IS_240x320_SCREEN) {
      DrawUtils.drawUserInfo(g, Global.currentUser.getName(), 235, 225, true);
    } else {
      DrawUtils.drawUserInfo(g, Global.currentUser.getName(), 315, 145, true);
    }

    // Vẽ con trỏ
    g.drawImage(pointerImage, BOARD_DX + CELL_SIZE / 2 - 2 + CELL_SIZE * (currentX - dColumn), BOARD_DY + CELL_SIZE / 2 + CELL_SIZE * (currentY - dRow), GameConstants.TOP_LEFT_ANCHOR);

    // Vẽ đếm thời gian và báo lượt đi
    if ((currentGameStatus != SHOW_FINAL_RESULL) && (currentGameStatus != SHOW_WIN_OR_LOST_ALERT_STATUS)) {
      if ((currentTurn == mySide)) {
        if (Constants.IS_240x320_SCREEN) {
          g.drawImage(numberBgImage, 185, 240, GameConstants.CENTER_ANCHOR);
          text8.drawString2(g, String.valueOf(timeMove), GameColor.WHITE_CODE, 185, 240, GameConstants.CENTER_ANCHOR);
        } else {
          g.drawImage(numberBgImage, 290, 130, GameConstants.CENTER_ANCHOR);
          text8.drawString2(g, String.valueOf(timeMove), GameColor.WHITE_CODE, 290, 130, GameConstants.CENTER_ANCHOR);
        }
      }
    }
    
    // Vẽ command
    if ((currentGameStatus == SHOW_FINAL_RESULL) || (currentGameStatus == SHOW_WIN_OR_LOST_ALERT_STATUS)) {
      DrawUtils.setBottomBar(_manager, "", "Chơi tiếp", "Thoát");
    } else {
      DrawUtils.setBottomBar(_manager, "", "", "Thoát");
    }
    
    // Draw chat
    Global.drawChat(g);

    switch (currentGameStatus) {
    case SHOW_WIN_OR_LOST_ALERT_STATUS:
      g.drawImage(matnaImage, 0, 0, GameConstants.TOP_LEFT_ANCHOR);
      g.drawImage(starImage, GameConstants.SCREEN_WIDTH / 2, (GameConstants.SCREEN_HEIGHT - 20) / 2, GameConstants.CENTER_ANCHOR);

      if (winReason == NORMAL_WIN_REASON) {
        g.setColor(GameColor.WHITE_CODE);
        g.drawLine((winPointX1 - dColumn) * CELL_SIZE + 5 + BOARD_DX, (winPointY1 - dRow) * CELL_SIZE + 5 + BOARD_DY, (winPointX2 - dColumn) * CELL_SIZE + 5 + BOARD_DX, (winPointY2 - dRow) * CELL_SIZE + 5 + BOARD_DY);
      }

      if (winSide == mySide) {
        g.drawImage(thangImage, GameConstants.SCREEN_WIDTH / 2, (GameConstants.SCREEN_HEIGHT - 20) / 2, GameConstants.CENTER_ANCHOR);
      } else {
        g.drawImage(thuaImage, GameConstants.SCREEN_WIDTH / 2, (GameConstants.SCREEN_HEIGHT - 20) / 2, GameConstants.CENTER_ANCHOR);
      }
      break;
    case SHOW_FINAL_RESULL:
      if (winReason == NORMAL_WIN_REASON) {
        g.setColor(GameColor.WHITE_CODE);
        g.drawLine((winPointX1 - dColumn) * CELL_SIZE + 5 + BOARD_DX, (winPointY1 - dRow) * CELL_SIZE + 5 + BOARD_DY, (winPointX2 - dColumn) * CELL_SIZE + 5 + BOARD_DX, (winPointY2 - dRow) * CELL_SIZE + 5 + BOARD_DY);
      }
      drawMoneyChangeNotification(g);
      break;
    case CHAT_STATUS:
      break;
    }
  }

  public void keyReleased(int keyCode) {
    if (currentGameStatus == WAIT_FOR_INIT_STATUS) {
      return;
    }
    isTurnOnAutoCamera = false;

    if (currentGameStatus == SHOW_WIN_OR_LOST_ALERT_STATUS) {
      if (keyCode == Key.FIRE) {
        currentGameStatus = SHOW_FINAL_RESULL;
      } else if (keyCode == Key.SOFT_RIGHT) {
        GameGlobal.nextState(FrmGroupTableFreeUserFriend.instance(), null);
      }
      return;
    }

    if (currentGameStatus == SHOW_FINAL_RESULL) {
      if ((keyCode == Key.FIRE) || (keyCode == Key.SOFT_RIGHT)) {
        GameGlobal.nextState(FrmGroupTableFreeUserFriend.instance(), null);
      }
      return;
    }
    
    if (!Key.isCommandKey) {
      if (Global.chatComponent != null) {
        Global.chatComponent.setShowInputChatMessageTextField(true);
        Global.chatComponent.keyReleased(keyCode);
      }
      return;
    }

    switch (keyCode) {
    case Key.UP:
      if (currentY > dRow) {
        currentY--;
      } else if (dRow > 0) {
        if (dRow > minRow - NUMBER_ROW_DISPLAY / 2) {
          dRow--;
          currentY--;
        }
      }
      break;
    case Key.DOWN:
      if (currentY < dRow + NUMBER_ROW_DISPLAY - 1) {
        currentY++;
      } else if (dRow < NUMBER_OF_ROW) {
        if (dRow < maxRow - NUMBER_ROW_DISPLAY / 2) {
          dRow++;
          currentY++;
        }
      }
      break;
    case Key.LEFT:
      if (currentX > dColumn) {
        currentX--;
      } else if (dColumn > 0) {
        if (dColumn > minColumn - NUMBER_COLUMN_DISPLAY / 2) {
          dColumn--;
          currentX--;
        }
      }
      break;
    case Key.RIGHT:
      if (currentX < dColumn + NUMBER_COLUMN_DISPLAY - 1) {
        currentX++;
      } else if (dColumn < NUMBER_OF_COLUMN) {
        if (dColumn < maxColumn - NUMBER_COLUMN_DISPLAY / 2) {
          dColumn++;
          currentX++;
        }
      }
      break;
    case Key.SOFT_RIGHT:
      if (Global.isShowedInputChatBox()) {
        Global.chatComponent.getChatTextField().deleteLastChar();
      } else {
        if ((currentGameStatus != SHOW_FINAL_RESULL) && (currentGameStatus != SHOW_WIN_OR_LOST_ALERT_STATUS)) {
          GameGlobal.alert.showAlert1(this, GameAlert.YES_NO_TYPE, StringArray.create1("Thoát ra bị tính là thua cuộc", "Bạn có muốn thoát ra?"), 98);
        }
      }
      break;
    case Key.SOFT_LEFT:
      Global.hideInputChatBox();
      break;
    case Key.FIRE:
      if (Global.isShowedInputChatBox()) {
        SocketClientUtil.sendMessage(Global.chatComponent.getCurrentRoomId(), Global.chatComponent.getChatTextField().getText());
        Global.hideInputChatBox();
        return;
      }
      
      if (matrix[currentX][currentY] != 0) {
        return;
      }

      if (mySide != currentTurn) {
        return;
      }

      fire(mySide, currentX, currentY);
      break;
    }
  }

  private void fire(int side, int x, int y) {
    matrix[x][y] = side;

    if (side == mySide) {
      // Gửi yêu cầu đánh
      DataPackage dataPackage = Game.createGamePackage(MOVE_REQUEST);
      dataPackage.putInt(x);
      dataPackage.putInt(y);
      Global.gameActionClient.write(dataPackage);
      currentTurn = opponentSide;
    } else {
      // Turn on camera
      desX = x;
      desY = y;
      recalculateGround(x, y);
      isTurnOnAutoCamera = true;

      // Change turn
      currentTurn = mySide;
    }
    timeMove = TIME_PER_MOVE;
  }

  private void recalculateGround(int cellX, int cellY) {
    if (minRow > cellY) {
      minRow = cellY;
    }
    if (maxRow < cellY) {
      maxRow = cellY;
    }
    if (minColumn > cellX) {
      minColumn = cellX;
    }
    if (maxColumn < cellX) {
      maxColumn = cellX;
    }
  }

  public void alertEventPerform(int alertType, int eventType, int alertId) {
    if (alertId == 98) { // Sự kiện thoát ra giữa ván
      if (eventType == GameAlert.YES_BUTTON) {
        SocketClientUtil.leaveTableRequest();
        GameGlobal.nextState(FrmGroupListTableFreeUserChat.instance(), null);
      }
      return;
    } else if (alertId == 97) { // Sự kiện báo đối phương đã thoát hoặc time out
      currentGameStatus = SHOW_FINAL_RESULL;
    }
  }

  public void doTask() {
    count = (count + 1) % 200;
    if (count % 10 == 0) {
      if (timeMove > 0) {
        timeMove--;
      }
    }
    runAutoCamera();
    
    if (moneyChangeIndex > -1) {
      moneyChangeIndex++;
      if (moneyChangeIndex > 50) {
        moneyChangeIndex = -1;
      }
    }
  }

  private void runAutoCamera() {
    if (isTurnOnAutoCamera) {
      if (dColumn < desX - NUMBER_COLUMN_DISPLAY / 2 && dColumn + NUMBER_COLUMN_DISPLAY < NUMBER_OF_COLUMN) {
        dColumn++;
        currentX++;
      } else if (dColumn > desX - NUMBER_COLUMN_DISPLAY / 2 && dColumn > 0) {
        dColumn--;
        currentX--;
      }
      if (dRow < desY - NUMBER_ROW_DISPLAY / 2 && dRow + NUMBER_ROW_DISPLAY < NUMBER_OF_ROW) {
        dRow++;
        currentY++;
      } else if (dRow > desY - NUMBER_ROW_DISPLAY / 2 && dRow > 0) {
        dRow--;
        currentY--;
      }
    }
  }

  public void destroy() {
    currentGameStatus = WAIT_FOR_INIT_STATUS;
    lastMoveImage = null;
    pointerImage = null;
    numberBgImage = null;
    matnaImage = null;
    starImage = null;
    thangImage = null;
    thuaImage = null;
    oponentName = null;

    text8 = null;
    oponentName = null;
    
    currentTurn = 0;
    mySide = 0;
    opponentSide = 0;
  }

  public void onConnectDone() {
  }

  public void onConnectFail() {
  }

  public void onDisconnect() {
  }
}
